#include "cpu.h"
#include <system/regs.h>
#include <klibc/stdio.h>
#include <klibc/ctype.h>


/*
 * Restituisce il "read time stamp counter"
 */
uint64_t cpu_rdtsc()
{
	regs_t r;
	//int highest;
	asm volatile("rdtsc":"=a"(r.eax),"=b"(r.ebx),
                 "=c"(r.ecx),"=d"(r.edx));	
                 
	return (r.edx << 32) + r.eax;
}


/*
 * Restituisce la frequenza di lavoro del processore
 */
uint32_t cpu_get_freq()
{
	uint64_t a;
	uint64_t b;
	
	a = cpu_rdtsc();
	timer_sleep(1000);
	b = cpu_rdtsc();
	
	uint32_t c = 1 / ((uint32_t) (b - a));
	
	return c;
}

/*
 * Esegue il commando cpuid restituendo i registre
 */
regs_t cpu_cpuid(int code)
{
	regs_t r;
	//int highest;
	asm volatile("cpuid":"=a"(r.eax),"=b"(r.ebx),
                 "=c"(r.ecx),"=d"(r.edx):"0"(code));
	//return highest;
	return r;
}


/*
 * Cpu features definisce delle costanti
 */
void cpu_features()
{
	regs_t r = cpu_cpuid(0x01);
	int x;
	
	for(x = 0; x < 28; x++)
	{
		if((r.ecx & (1 << x)) == 1)
			CPU_FEATURES = CPU_FEATURES + (1 << x);
	}

	for(x = 0; x < 28; x++)
	{
		if((r.edx & (1 << x)) == 1)
			CPU_FEATURES = CPU_FEATURES + (1 << (28 + x));
	}
}

/*
 * Get if a feature is active
 */
uint8_t cpu_iffeature(uint8_t f)
{
	return (CPU_FEATURES & (1 << f));
}

/*
 * Restituisce una stringa con il nome del processore
 */
void cpu_vendor_name()
{
		regs_t r = cpu_cpuid(0x00);
		
		MAX_CPUID_CODE = r.eax;
		
		char line1[5];
		line1[0] = ((char *) &r.ebx)[0];
		line1[1] = ((char *) &r.ebx)[1];
		line1[2] = ((char *) &r.ebx)[2];
		line1[3] = ((char *) &r.ebx)[3];
		line1[4] = '\0';

		char line2[5];
		line2[0] = ((char *) &r.ecx)[0];
		line2[1] = ((char *) &r.ecx)[1];
		line2[2] = ((char *) &r.ecx)[2];
		line2[3] = ((char *) &r.ecx)[3];
		line2[4] = '\0';
		
		char line3[5];
		line3[0] = ((char *) &r.edx)[0];
		line3[1] = ((char *) &r.edx)[1];
		line3[2] = ((char *) &r.edx)[2];
		line3[3] = ((char *) &r.edx)[3];
		line3[4] = '\0';
							
			
		strcpy(CPU_VENDOR_NAME, line1);
		strcat(CPU_VENDOR_NAME, line3);
		strcat(CPU_VENDOR_NAME, line2);
}


void cpu_init()
{
	cpu_vendor_name();
	cpu_features();
	
	
	//printf("%d %d %d\n", cpu_iffeature(CPU_FEAT_APIC), cpu_iffeature(CPU_FEAT_IA64), cpu_iffeature(CPU_FEAT_APIC));
}

